package com.yiji.fintech.musfinance.common.strategy.notify;

import com.acooly.core.common.exception.OrderCheckException;
import com.acooly.core.utils.enums.Messageable;
import com.acooly.core.utils.enums.ResultStatus;
import com.acooly.core.utils.mapper.BeanCopier;
import com.acooly.core.utils.validate.Validators;
import com.alibaba.dubbo.config.annotation.Reference;
import com.google.common.collect.Lists;
import com.yiji.fintech.musfinance.base.enums.NotifyStatusEnum;
import com.yiji.fintech.musfinance.center.base.order.OrderFacade;
import com.yiji.fintech.musfinance.center.notify.api.thirdparty.PactNotifyFacade;
import com.yiji.fintech.musfinance.center.notify.order.base.NotifyOrderBase;
import com.yiji.fintech.musfinance.center.notify.order.thirdparty.PactNotifyOrder;
import com.yiji.fintech.musfinance.center.notify.result.NotifyResult;
import com.yiji.fintech.musfinance.center.notify.result.PactNotifyResult;
import com.yiji.fintech.musfinance.common.annotation.LogAspectAnnotation;
import com.yiji.fintech.musfinance.common.service.OpratorService;
import com.yiji.fintech.musfinance.common.utils.BizAssert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

/**
 * Created by ouwen@yiji.com} on 2017/9/25.
 */
@Slf4j
public abstract class AbstractNotifyStrategy extends OpratorService implements NotifyStrategyBase{

    @Reference(version = "1.0",group = "com.born.bfintech.facade.musfinanceNotifyRecevier")
    protected PactNotifyFacade pactNotifyFacade;

    @LogAspectAnnotation("notifyStrategy")
    @Override
    public NotifyResult doExcute(NotifyOrderBase notifyOrder,NotifyResult result) {
        checkOrder(notifyOrder);//order交易
        initDbService(this);//初始化数据库服务
        unique(notifyOrder);//通过交易流水号获取校验订单是否存在
        if(isNotify()) {//是否通知业务方
            notifyPact(notifyOrder,result);//异步通知业务系统
            updateTransAction(notifyOrder,result);//更新流水
        }
        return result;
    }
    protected void checkOrder(OrderFacade order){
        if (null == order) {
            throw new OrderCheckException();
        }
        try {
            Validators.assertJSR303(order);
            order.check();
        } catch (IllegalArgumentException iae) {
            throw new OrderCheckException(iae.getMessage(), "请求参数不完整:");
        } catch (Exception e) {
            throw new OrderCheckException(StringUtils.left(e.getMessage(), 200),"公共参数合法性检查未通过:");
        }
    }
    /**
     * 交易订单是否需要通知第三方
     */
    private boolean isNotify(){
        if(Lists.newArrayList(NotifyStatusEnum.FAIL,NotifyStatusEnum.NO).contains(entity.getNotifyStatus())){
            return true;
        }
        return false;
    }
    /**
     * 订单是否存在校验
     * @param notifyOrder
     */
    private void unique(NotifyOrderBase notifyOrder){
        findEntity(notifyOrder);//通过流水号查找订单
        BizAssert.notNull(entity,"异步通知订单交易内部流水【"+notifyOrder.getBizOrderNo()+"】不存在");
    }

    /**
     * 更新流水
     * @param notifyOrder
     */
    private void updateTransAction(NotifyOrderBase notifyOrder,NotifyResult result) {
        BeanCopier.copy(notifyOrder,entity,BeanCopier.CopyStrategy.IGNORE_NULL, BeanCopier.NoMatchingRule.IGNORE,null);
        if(ResultStatus.failure == result.getStatus()){
            entity.setNotifyStatus(NotifyStatusEnum.FAIL);//通知失败
        }else{
            entity.setNotifyStatus(NotifyStatusEnum.SUCCESS);//通知成功
        }
        service.update(entity); //更新流水
    }

    /**
     * 初始化通知业务方order
     * 根据业务需求重载该方法
     * @param notifyOrder
     * @return
     */
    protected PactNotifyOrder initPackNotifyOrder(NotifyOrderBase notifyOrder) {
        PactNotifyOrder pactNotifyOrder = new PactNotifyOrder();
        BeanCopier.copy(notifyOrder,pactNotifyOrder,BeanCopier.CopyStrategy.IGNORE_NULL, BeanCopier.NoMatchingRule.IGNORE,null);
        pactNotifyOrder.setTradeType(entity.getTradeType());
        return pactNotifyOrder;
    }
    /**
     * 通知业务方
     * @param notifyOrder
     * @param result
     */
    private void notifyPact(NotifyOrderBase notifyOrder,NotifyResult result){
        PactNotifyResult pactNotifyResult;
        Messageable status;
        String detail,code;
        try {
            PactNotifyOrder pactNotifyOrder = initPackNotifyOrder(notifyOrder);
            pactNotifyResult = pactNotifyFacade.notify(pactNotifyOrder);
            status = pactNotifyResult.getStatus();
            code = pactNotifyResult.getCode();
            detail = pactNotifyResult.getDetail();
        } catch (Exception e) {
            status = ResultStatus.failure;
            code = ResultStatus.failure.getCode();
            detail = e.getMessage();
            log.error("GID【{}】外部流水号【{}】内部流水号【{}】异步通知业务方异常",notifyOrder.getGid(),notifyOrder.getMerchOrderNo(),notifyOrder.getBizOrderNo(),e.getMessage());
        }
        //返回网关结果状态
        result.setStatus(status);
        result.setCode(code);
        result.setDetail(detail);
    }
}
